<!DOCTYPE html>



  


<html class="theme-next gemini use-motion" lang="chinese">
<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">



  
  
    
      
    
    
      
    
  <script src="//cdn.jsdelivr.net/npm/pace-js@1/pace.min.js"></script>
  <link href="//cdn.jsdelivr.net/npm/pace-js@1/themes/blue/pace-theme-minimal.min.css" rel="stylesheet">







<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT">










<meta name="description" content="第十四章 类型信息&amp;emsp;&amp;emsp;RTTI（Run-Time-Type-Information），运行时类型信息。本章讲解Java 如何在编译时期识别对象和类的信息。另一种是“反射”机制，它允许在运行时候发现和使用类的信息。 15.1 为什么需要RTTI&amp;emsp;&amp;emsp;在多态的过程中，基类的派生类使用基类提供的方法时，动态绑定以及向上转型相关，在最后阶段运行过程中找到自己对应的派生">
<meta name="keywords" content="Java Php hexo Thinking in Java">
<meta property="og:type" content="article">
<meta property="og:title" content="Thinking in Java 第十四章">
<meta property="og:url" content="http://yoursite.com/2019/08/10/Thinking-in-Java-第十四章/index.html">
<meta property="og:site_name" content="坚持就是胜利">
<meta property="og:description" content="第十四章 类型信息&amp;emsp;&amp;emsp;RTTI（Run-Time-Type-Information），运行时类型信息。本章讲解Java 如何在编译时期识别对象和类的信息。另一种是“反射”机制，它允许在运行时候发现和使用类的信息。 15.1 为什么需要RTTI&amp;emsp;&amp;emsp;在多态的过程中，基类的派生类使用基类提供的方法时，动态绑定以及向上转型相关，在最后阶段运行过程中找到自己对应的派生">
<meta property="og:locale" content="chinese">
<meta property="og:updated_time" content="2019-08-11T13:21:58.395Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Thinking in Java 第十四章">
<meta name="twitter:description" content="第十四章 类型信息&amp;emsp;&amp;emsp;RTTI（Run-Time-Type-Information），运行时类型信息。本章讲解Java 如何在编译时期识别对象和类的信息。另一种是“反射”机制，它允许在运行时候发现和使用类的信息。 15.1 为什么需要RTTI&amp;emsp;&amp;emsp;在多态的过程中，基类的派生类使用基类提供的方法时，动态绑定以及向上转型相关，在最后阶段运行过程中找到自己对应的派生">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":14,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '190coder'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/2019/08/10/Thinking-in-Java-第十四章/">





  <title>Thinking in Java 第十四章 | 坚持就是胜利</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="chinese">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">坚持就是胜利</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br>
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br>
            
            Categories
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
            
            Archives
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2019/08/10/Thinking-in-Java-第十四章/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="190coder">
      <meta itemprop="description" content>
      <meta itemprop="image" content="/images/avatar.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="坚持就是胜利">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Thinking in Java 第十四章</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2019-08-10T23:35:23+08:00">
                2019-08-10
              </time>
            

            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">In</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Java/" itemprop="url" rel="index">
                    <span itemprop="name">Java</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="第十四章-类型信息"><a href="#第十四章-类型信息" class="headerlink" title="第十四章 类型信息"></a>第十四章 类型信息</h1><p>&emsp;&emsp;RTTI（Run-Time-Type-Information），运行时类型信息。本章讲解Java 如何在编译时期识别对象和类的信息。另一种是“反射”机制，它允许在运行时候发现和使用类的信息。</p>
<h2 id="15-1-为什么需要RTTI"><a href="#15-1-为什么需要RTTI" class="headerlink" title="15.1 为什么需要RTTI"></a>15.1 为什么需要RTTI</h2><p>&emsp;&emsp;在多态的过程中，基类的派生类使用基类提供的方法时，动态绑定以及向上转型相关，在最后阶段运行过程中找到自己对应的派生类。也正是有了RTTI，编译器才能正确的找到对应的派生类。上述思想是Java中多态思想的体现，多态也是Java中设计的关键思想，尽量使代码尽可能少的了解其具体的类型，而只与通用的类（基类）打交道。这种设计使代码逻辑更加简单、易于理解。</p>
<h2 id="15-2-Class对象"><a href="#15-2-Class对象" class="headerlink" title="15.2 Class对象"></a>15.2 Class对象</h2><p>&emsp;&emsp;要理解RTTI在Java中的工作原理，首先要知道类型信息在运行时是如何表示的。这项工作是由称为Class对象的一种特殊的对象表示的。面向对象思想告诉我们，万事万物都是对象，Java中除了基本的数据类型，其它的都是对象。那么如果我们有如下代码：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Student s = new Student();</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;我们使用new Student（）创建了一个Student类的对象，那么Student类又是不是对象呢？没错，如前文所说，万事万物都是对象，这里Student就是Class的对象，也就是说任何声明定义的类，都是Class类的类对象。当编译器编译完一个类时，在同名的.class文件中就会保存这个类的Class对象。而为了生成这个对象，运行这个类的JVM会使用一个称作是“类加载器”的子系统。</p>
<p>&emsp;&emsp;类加载器子系统实际上可以包含一条类加载器链，但只有一个原生的类加载器，它是JVM实现的一部分，用来加载所谓的可信类，以及JavaAPI。如果还需要其它特殊的操作，比如支持Web服务应用，或者是在网络上下载类，那么就可以在类加载器链上挂载额外的类加载器。</p>
<p>&emsp;&emsp;所有的类在其第一次加载的时候，都被动态的加载到JVM中，当程序创建第一个类的静态成员引用时，就会被加载。这也说明类的构造器也是类的静态方法，即使在构造器之前并没有使用static关键字。因此使用new关键词创建的类的新的对象，也会被当做是类的静态成员引用。也正是如此，Java程序在运行之前并非完全加载，动态加载在诸如C++这类的静态加载语言是无法实现的。</p>
<p>&emsp;&emsp;一旦某个类的Class对象被载入内存，它就用来创建这个类的所有对象，如下示例说明这点：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">class Candy&#123;</span><br><span class="line">	static&#123;</span><br><span class="line">		System.out.println(&quot;Loading Candy&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">class Gum&#123;</span><br><span class="line">	static&#123;</span><br><span class="line">		System.out.println(&quot;Loading Gum&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">class Cookie&#123;</span><br><span class="line">	static&#123;</span><br><span class="line">		System.out.println(&quot;Loading Cookie&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">public class SweetShop &#123;</span><br><span class="line">	public static void main(String[] args) &#123;</span><br><span class="line">		System.out.println(&quot;Inside main&quot;);</span><br><span class="line">		new Candy();</span><br><span class="line">		System.out.println(&quot;After Creating Candy&quot;);</span><br><span class="line">		try&#123;</span><br><span class="line">			Class.forName(&quot;com.chenxyt.java.practice.Gum&quot;);</span><br><span class="line">		&#125;catch(ClassNotFoundException e)&#123;</span><br><span class="line">			System.err.println(&quot;Gum Not found&quot;);</span><br><span class="line">		&#125;</span><br><span class="line">		System.out.println(&quot;After Creating Gum&quot;);</span><br><span class="line">		new Cookie();</span><br><span class="line">		System.out.println(&quot;After Creating Cookie&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;Class对象仅在需要的时候被加载，static初始化是在类加载时候进行的。需要注意的是Class.forName（）这个方法，它是Class类的一个静态方法，所有的类都是Class类的对象，forName（）是取得Class对象引用的一种方法。它使用目标类名作为参数，返回Class对象的引用。如果找不到指定的类名则抛出ClassNotFound异常。无论何时你想获取到类的运行时使用的类型信息，就必须要获得恰当的Class对象的引用，Class.forName（）是实现此功能的捷径。因此你不需要为了获得Class对象的引用而持有该类型的对象。但是如果你已经拥有了一个指定类型的对象，那么就可以使用.getClass方法获取Class对象的引用。这个方法属于Object，它将返回表示该对象实际类型的Class对象引用。</p>
<p><strong>Java中除了以上两种Class.forName()和obj.getClass()可以产生类的对象引用，还有一种类字面常量的形式：</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">FancyToy.class：</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;这样做不仅简单，而且更加安全，因为在编译时即可检查，无需使用try-catch语句，所以更加高效。类字面常量不仅可以应用与普通的类，还可以应用在基本数据类型，以及接口和数组中。此外对于基本数据类型的包装器类，它还有个TYPE字段，TYPE是一个引用，指向对应的基本数据类型的Class对象。<br>&emsp;&emsp;此处有一点非常重要需要注意，当使用.class来创建对象的引用时，不会自动的初始化该Class对象。为了使用类而做的准备工作实际上包含三个步骤：</p>
<ol>
<li>加载：这是由类加载器执行的，该步骤将查找字节码（通常在classpath路径查找，但不是必须的），并从这些字节码中创建一个Class对象；</li>
<li>链接：在链接阶段验证类的字节码，为静态域分配存储空间，并且如果必要的话，会解析这个类创建的对其它类的所有引用；</li>
<li>初始化：如果该类具有超类，则对其进行初始化，执行静态初始化器和静态初始化块。<br>初始化被延迟到了对静态方法（构造器也是隐式的静态方法）或者非常数静态域进行首次引用时才执行：<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">import java.util.Random;</span><br><span class="line">class Initable&#123;</span><br><span class="line"> static final int staticFinal = 45;</span><br><span class="line"> static final int staticFinal2 = ClassInitialization.rand.nextInt(1000);</span><br><span class="line"> static&#123;</span><br><span class="line">  System.out.println(&quot;Initializing Initable&quot;);</span><br><span class="line">  System.out.println(&quot;Initable---------------&quot;);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line">class Initable2&#123;</span><br><span class="line"> static int staticNonFinal = 145;</span><br><span class="line"> static&#123;</span><br><span class="line">  System.out.println(&quot;Initializing Initable2&quot;);</span><br><span class="line">  System.out.println(&quot;Initable2---------------&quot;);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line">class Initable3&#123;</span><br><span class="line"> static int staticNonFinal = 54;</span><br><span class="line"> static&#123;</span><br><span class="line">  System.out.println(&quot;Initializing Initable3&quot;);</span><br><span class="line">  System.out.println(&quot;Initable3---------------&quot;);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line">public class ClassInitialization &#123;</span><br><span class="line"> public static Random rand = new Random(45);</span><br><span class="line"> public static void main(String[] args) throws ClassNotFoundException &#123;</span><br><span class="line">  Class initable = Initable.class;</span><br><span class="line">  System.out.println(&quot;After Creating Initable Ref&quot;);</span><br><span class="line">  System.out.println(Initable.staticFinal);</span><br><span class="line">  System.out.println(&quot;------------------&quot;);</span><br><span class="line">  System.out.println(Initable.staticFinal2);</span><br><span class="line">  System.out.println(Initable2.staticNonFinal);</span><br><span class="line">  Class initable3 = Class.forName(&quot;com.chenxyt.java.practice.Initable3&quot;);</span><br><span class="line">  System.out.println(&quot;After Creating Initable3 Ref&quot;);</span><br><span class="line">  System.out.println(Initable3.staticNonFinal);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ol>
<p>.class并不会引发初始化，相反使用Class.forName（）时则立刻完成了初始化的功能。同时，如果一个域被声明为static final的编译时常量，那么它可以不初始化类就被访问，就像Initable.staticFinal一样，但是仅仅被声明为static final并不会保证类不被初始化就能访问，就像Intable.staticFinal2那样，因为它不是编译时常量。<br>    如果一个static域不是final的，那么在对它访问的时候，总是要求在读取之前先进行链接（为这个域分配存储空间）和初始化（初始化该存储空间），就像在对Initable2.staticNonFinal的访问中看到这样。</p>
<p>Class类允许使用泛型指定相应的类型，如下两种形式均可：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">public class GenericClassReference &#123;</span><br><span class="line">	public static void main(String[] args) &#123;</span><br><span class="line">		Class intClass = int.class;</span><br><span class="line">		Class&lt;Integer&gt; genericIntClass = int.class;</span><br><span class="line">		genericIntClass = Integer.class;</span><br><span class="line">		intClass = double.class;</span><br><span class="line">		//类型不匹配</span><br><span class="line">	//	genericIntClass = double.class;</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;普通的类引用不会产生警告信息，并可以被重新指定为其它类型的引用。而泛型类的引用只能被指定为指定的类型。通过使用泛型语法，可以使编译器做一些额外的类型检查。如果我们希望放松这种限制，那么似乎可以使用：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class&lt;Number&gt; genericClass = int.class;</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;因为Integer类继承自Number类，但实际上并不可以正常工作，因为Integer Class对象不是Number Class对象的子类。为了放松这种类型的限制，我们使用了通配符，它是Java泛型的一部分。通配符就是“？”表示任何事物。</p>
<p>&emsp;&emsp;尽管看起来这种形式与直接使用Class相同，但是它不会产生编译器警告信息。更确切的说使用通配符表示的是你并非是碰巧或者是由于疏忽而选择了一个非具体类的引用，而是你就是明确的选择了一个非具体的版本。使用通配符与extends关键字，可以有效的解决前边所说的继承的问题：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Class&lt;? extends Number&gt; genericClass = int.class;</span><br></pre></td></tr></table></figure>

<p>表示创建一个Number 或是它子类的类对象。</p>
<h2 id="14-3-类型转换器先做检查"><a href="#14-3-类型转换器先做检查" class="headerlink" title="14.3 类型转换器先做检查"></a>14.3 类型转换器先做检查</h2><p>&emsp;&emsp;类型转换信息有两种，一种是传统的类型转换，由RTTI确保类型转换，如果执行了一个错误的类型转换，那么将抛出一个ClassCastException异常，另一种是代表对象类类型的Class对象，通过查询Class对象的信息获取运行时的所有状态。RTTI在Java中还有第三种类型转换的形式，就是使用关键字instanceof，它返回布尔值，判断某个对象是不是某个特定类的实例。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">if(x instanceof Dog)&#123;</span><br><span class="line">    (Dog)x.bark();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;这种先进行判断然后再使用的方式显得很必然，比如在进行向下转型的时候，如果不先进行判断，很容易发生ClassCastException异常。此外也提供了动态判断的形式isInstanceof（）方法。</p>
<h2 id="14-4-注册工厂"><a href="#14-4-注册工厂" class="headerlink" title="14.4 注册工厂"></a>14.4 注册工厂</h2><p>&emsp;&emsp;使用注册工厂的目的是将对象的创建工作交给类去完成，即创建一个工厂方法，然后进行多态的调用，从而为你创建恰当类型的对象。在如下的简单的版本中，工厂方法就是Factory接口中的Create方法。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">public interface Factory&lt;T&gt;&#123;T create();&#125;</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;工厂方法，就是意味着我只提供一个创建实例的工厂方法，而无需每创建一个继承类就编写一个新的方法。关于工厂方法更多细节后边在设计模式模块专门再进行学习。</p>
<h2 id="14-5-instanceof与Class的等价性"><a href="#14-5-instanceof与Class的等价性" class="headerlink" title="14.5 instanceof与Class的等价性"></a>14.5 instanceof与Class的等价性</h2><p>instanceof与直接比较Class对象有一点很重要的区别</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">class BaseType&#123;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line">class Derived extends BaseType&#123;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line">public class FamilyVsExactType &#123;</span><br><span class="line">	static void test(Object x)&#123;</span><br><span class="line">		System.out.println(&quot;Testing x of type&quot; + x.getClass());</span><br><span class="line">		System.out.println(&quot;x instance of BaseType&quot; + (x instanceof BaseType));</span><br><span class="line">		System.out.println(&quot;x instance of Derived&quot; + (x instanceof Derived));</span><br><span class="line">		System.out.println(&quot;BaseType.isInstance(x)&quot; + BaseType.class.isInstance(x));</span><br><span class="line">		System.out.println(&quot;Derived isInstance(x)&quot; + Derived.class.isInstance(x));</span><br><span class="line">		System.out.println(&quot;x.getClass == BaseType.class&quot; + (x.getClass() == BaseType.class));</span><br><span class="line">		System.out.println(&quot;x.getClass == Derived.class&quot; + (x.getClass() == Derived.class));</span><br><span class="line">		System.out.println(&quot;x.getClass.equals(BaseType.class)&quot; + (x.getClass().equals(BaseType.class)));</span><br><span class="line">		System.out.println(&quot;x.getClass.equals(Derived.class)&quot; + (x.getClass().equals(Derived.class)));</span><br><span class="line">	&#125;</span><br><span class="line">	public static void main(String[] args) &#123;</span><br><span class="line">		test(new BaseType());</span><br><span class="line">		test(new Derived());</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>instanceof表示的是“你是这个类吗？或者你是这个类的子类吗？”而使用Class对象进行比较时，表示的则只有明确的类型信息，忽略了继承的关系。</p>
<h2 id="14-6-反射：运行时类型信息"><a href="#14-6-反射：运行时类型信息" class="headerlink" title="14.6 反射：运行时类型信息"></a>14.6 反射：运行时类型信息</h2><p>&emsp;&emsp;程序在编译的时候并不知道具体的类型信息，直到程序运行时通过反射才获取到了准确的类信息。这里提供了几个方法支持获取准确的类信息，以便创建动态的代码。使用Class类的getMethods（）方法可以获取这个类所包含的所有方法，使用getConstructors（）方法可以获取这个类的所有构造函数。前文也提到过，使用Class.forName（）可以用来动态的加载类。它的生成结果在编译的时候是不可知的，因此所有的方法特征信息和签名都是在运行时被提取出来的。</p>
<h2 id="14-7-动态代理"><a href="#14-7-动态代理" class="headerlink" title="14.7 动态代理"></a>14.7 动态代理</h2><p>&emsp;&emsp;代理是常用的设计模式之一，它的作用是在基本的对象操作之外，增加一些其它额外的操作。比如我想使用一个对象，同事想了解这个对象的运行过程，那么这个运行过程的监控显然就不能放在基本的对象代码中。有点类似前面文章中提到的组合类的思想，新建一个代理类，代理类引用要使用的对象，然后增加一些新的功能。<br>&emsp;&emsp;可以把代理模式类比成是中介，中介的目的是卖东西的基础上赚钱，卖东西就是基本操作，赚钱就是中介也就是代理做的额外的操作。下面一个示例展示简单的代理模式：</p>
<p>定义一个接口：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">public interface Interface &#123;</span><br><span class="line">	void doSomeThing();</span><br><span class="line">	void somethingElse(String arg);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个接口的实现类，也就是前边所说的真正要操作的运行的对象：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">public class RealObject implements Interface &#123;</span><br><span class="line"> </span><br><span class="line">	@Override</span><br><span class="line">	public void doSomeThing() &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;RealObject DoSomeThing&quot;);</span><br><span class="line">	&#125;</span><br><span class="line"> </span><br><span class="line">	@Override</span><br><span class="line">	public void somethingElse(String arg) &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;RealObject somethingElse&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>定义一个代理类，代理类实现了Interface接口，同时通过传参的形式传入了前边的实现类，在完成实现类功能的基础上，做了自己的操作：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">public class SimpleProxy implements Interface&#123;</span><br><span class="line">	</span><br><span class="line">	private Interface proxied;</span><br><span class="line">	</span><br><span class="line">	public SimpleProxy(Interface proxied) &#123;</span><br><span class="line">		// TODO Auto-generated constructor stub</span><br><span class="line">		this.proxied = proxied;</span><br><span class="line">	&#125;</span><br><span class="line">	@Override</span><br><span class="line">	public void doSomeThing() &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;Proxy DoSomething&quot;);</span><br><span class="line">		proxied.doSomeThing();</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">	@Override</span><br><span class="line">	public void somethingElse(String arg) &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;Proxy somethingElse&quot;);</span><br><span class="line">		proxied.somethingElse(arg);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>然后是这个接口的实现类，也就是前边所说的真正要操作的运行的对象：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">public class RealObject implements Interface &#123;</span><br><span class="line"> </span><br><span class="line">	@Override</span><br><span class="line">	public void doSomeThing() &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;RealObject DoSomeThing&quot;);</span><br><span class="line">	&#125;</span><br><span class="line"> </span><br><span class="line">	@Override</span><br><span class="line">	public void somethingElse(String arg) &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;RealObject somethingElse&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p> 然后定义一个代理类，代理类实现了Interface接口，同时通过传参的形式传入了前边的实现类，在完成实现类功能的基础上，做了自己的操作：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">public class SimpleProxy implements Interface&#123;</span><br><span class="line">	</span><br><span class="line">	private Interface proxied;</span><br><span class="line">	</span><br><span class="line">	public SimpleProxy(Interface proxied) &#123;</span><br><span class="line">		// TODO Auto-generated constructor stub</span><br><span class="line">		this.proxied = proxied;</span><br><span class="line">	&#125;</span><br><span class="line">	@Override</span><br><span class="line">	public void doSomeThing() &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;Proxy DoSomething&quot;);</span><br><span class="line">		proxied.doSomeThing();</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">	@Override</span><br><span class="line">	public void somethingElse(String arg) &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;Proxy somethingElse&quot;);</span><br><span class="line">		proxied.somethingElse(arg);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>最后是Main方法，因为consumer方法传参是Interface接口，所以任何实现了它接口的实体类都可以当做参数。这里演示了使用基本的实体类和使用代理的区别，代理在完成普通实体类的功能基础上打印了自己的操作内容：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">public class SimpleProxyDemo &#123;</span><br><span class="line">	public static void consumer(Interface iface)&#123;</span><br><span class="line">		iface.doSomeThing();</span><br><span class="line">		iface.somethingElse(&quot;bobo&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	public static void main(String[] args) &#123;</span><br><span class="line">		consumer(new RealObject());</span><br><span class="line">		System.out.println(&quot;==============&quot;);</span><br><span class="line">		consumer(new SimpleProxy(new RealObject()));</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;在任何时刻你若想实现一些与“实际”对象分离的额外操作，或者你希望很容易能对这部分操作做出修改，那么使用代理模式无疑是最为方便的。<br>&emsp;&emsp;Java的动态代理比代理的思想更向前迈进了一步，因为它可以动态的创建代理，并且动态的处理对所代理方法的调用。动态代理所做的所有操作都会被重定向到单一的调用处理器上，它的工作是揭示调用的类型，并确定相应的对策。下面用动态代理重写上边的示例。<br>&emsp;&emsp;Java中要实现动态代理类，必须要继承InvocationHandle这个类，这个类内部嵌入的对象是要被实现的真正的对象，同样使用构造方法传入，这个类唯一的一个方法invoke，它有三个参数，第一个参数是生成的动态代理类。既然动态代理是动态的创建代理，那么这个参数固然是所创建的动态代理，第二个参数是传入的对象执行的方法，第三个参数是传入的参数。最后将请求通过Method.invoke（）方法，传入必要的参数，执行代理对象的方法。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">import java.lang.reflect.InvocationHandler;</span><br><span class="line">import java.lang.reflect.Method;</span><br><span class="line"> </span><br><span class="line">public class DynamicProxyHandler implements InvocationHandler&#123;</span><br><span class="line">	</span><br><span class="line">	private Object proxied;</span><br><span class="line">	</span><br><span class="line">	public DynamicProxyHandler(Object proxied) &#123;</span><br><span class="line">		// TODO Auto-generated constructor stub</span><br><span class="line">		this.proxied = proxied;</span><br><span class="line">	&#125;</span><br><span class="line">	@Override</span><br><span class="line">	public Object invoke(Object proxy, Method method, Object[] args)</span><br><span class="line">			throws Throwable &#123;</span><br><span class="line">		System.out.println(&quot;**** Proxy:&quot; + proxy.getClass() + &quot;,method:&quot; + method + &quot;,args &quot; + args );</span><br><span class="line">		if(args!=null)&#123;</span><br><span class="line">			for(Object arg:args)&#123;</span><br><span class="line">				System.out.println(&quot;  &quot; + arg);</span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		return method.invoke(proxied, args);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>客户端类：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">import java.lang.reflect.Proxy;</span><br><span class="line"> </span><br><span class="line">public class SimpleDynamicProxyDemo &#123;</span><br><span class="line">	public static void consumer(Interface iface)&#123;</span><br><span class="line">		iface.doSomeThing();</span><br><span class="line">		iface.somethingElse(&quot;DIDI&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	public static void main(String[] args) &#123;</span><br><span class="line">		RealObject real = new RealObject();</span><br><span class="line">		consumer(real);</span><br><span class="line">		System.out.println(&quot;=========&quot;);</span><br><span class="line">		Interface proxy = (Interface)Proxy.newProxyInstance(Interface.class.getClassLoader(),new Class[]&#123;Interface.class&#125;,new DynamicProxyHandler(real));</span><br><span class="line">		consumer(proxy);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>&emsp;&emsp;客户端类使用Proxy.newProxyInstance（）方法创建了一个代理对象。第一个参数是一个加载器，这里用的是系统加载器，所以使用其它类的加载器结果也是一样的，第二个参数是代理对象要实现的接口，第三个参数是Handler对象，表示我这个代理对象在调用方法时，会映射关联到哪个Hnadler上去，这里是关联到了我们定义的DynamicProxyHandler上，然后转由它的invoke方法执行对象方法。</p>
<p>我们可以在代理方法invoke（）中对诸如方法名、参数进行过滤，只执行指定的方法。</p>
<p><strong>Spring的AOP核心思想就是动态代理，现在更加理解了一些，简单表述一下就是在切入点处执行一写其它操作，如我这里是记录日志，然后执行正常的业务方法。记录日志就是脱离在实际业务之外的一些操作。</strong></p>
<p>##</p>
<h2 id="14-8-空对象"><a href="#14-8-空对象" class="headerlink" title="14.8 空对象"></a>14.8 空对象</h2><p>&emsp;&emsp;当一个对象为null的时候，任何对这个对象的操作都会引发异常。为了避免这种情况，当一个对象为null的时候，我们定义一个空对象赋值给它。何谓空对象呢？就是一个不存在实际意义但是不会引发异常的对象。</p>
<h2 id="14-9-接口与类型信息"><a href="#14-9-接口与类型信息" class="headerlink" title="14.9 接口与类型信息"></a>14.9 接口与类型信息</h2><p>&emsp;&emsp;接口或者是面向接口编程的重要目的是实现隔离，也就是解耦。但是通过类型信息，这种耦合还是会传播出去。也就是接口对解耦来说，并不是绝对的。如下示例：</p>
<p>定义一个接口A，它有唯一一个方法f</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">public interface A&#123;</span><br><span class="line">	public void f();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接下来是接口的实现B，除了A中的方法，还有自己的方法g</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">public class B implements A&#123;</span><br><span class="line"> </span><br><span class="line">	@Override</span><br><span class="line">	public void f() &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">		System.out.println(&quot;method f&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	public void g()&#123;</span><br><span class="line">	    System.out.println(&quot;method g&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Main</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">public class InterfaceViolation &#123;</span><br><span class="line">	public static void main(String[] args) &#123;</span><br><span class="line">		A a = new B();</span><br><span class="line">		a.f();</span><br><span class="line">		System.out.println(&quot;a.getClass: &quot; + a.getClass().getName());</span><br><span class="line">		if(a instanceof B)&#123;</span><br><span class="line">			B b = (B)a;</span><br><span class="line">			b.g();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里通过使用RTTI，发现a是被当做B类型实现的，因此通过将其转型成B，可以调用了B中新加的方法。</p>
<p>    上面这种操作，完全合理并且可接受，但是提高了代码的耦合度，实际上并不允许这样做。解决办法是使用包访问权限来加以控制。</p>
<p>新定义一个实现类实现接口A：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">package com.chenxyt.java.practice;</span><br><span class="line"> </span><br><span class="line">class C implements A&#123;</span><br><span class="line">	@Override</span><br><span class="line">	public void f() &#123;</span><br><span class="line">		// TODO Auto-generated method stub</span><br><span class="line">	System.out.println(&quot;C.f&quot;);	</span><br><span class="line">	&#125;</span><br><span class="line">	public void g()&#123;</span><br><span class="line">		System.out.println(&quot;C.g&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	void u()&#123;</span><br><span class="line">		System.out.println(&quot;C.u&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	protected void v()&#123;</span><br><span class="line">		System.out.println(&quot;C.v&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">	private void w()&#123;</span><br><span class="line">		System.out.println(&quot;C.w&quot;);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">	public class HidenC&#123;</span><br><span class="line">		public static A makeA()&#123;</span><br><span class="line">			return new C();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>

<p>在另一个包中使用它：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">package com.chenxyt.java.test;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line">import java.lang.reflect.Method;</span><br><span class="line"> </span><br><span class="line">import com.chenxyt.java.practice.A;</span><br><span class="line">import com.chenxyt.java.practice.HidenC;</span><br><span class="line"> </span><br><span class="line">public class HiddenImplementation &#123;</span><br><span class="line">	public static void main(String[] args) throws Exception &#123;</span><br><span class="line">		A a = HidenC.makeA();</span><br><span class="line">		a.f();</span><br><span class="line">		System.out.println(&quot;a.getClass: &quot; + a.getClass().getName());</span><br><span class="line">		//编译错误 受包访问权限控制</span><br><span class="line">/*		if(a instanceof C)&#123;</span><br><span class="line">			C c = (C)a;</span><br><span class="line">			c.g();</span><br><span class="line">		&#125;*/</span><br><span class="line">		callHiddenMethod(a,&quot;g&quot;);</span><br><span class="line">		callHiddenMethod(a,&quot;v&quot;);</span><br><span class="line">		callHiddenMethod(a,&quot;u&quot;);</span><br><span class="line">		callHiddenMethod(a,&quot;w&quot;);</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">	static void callHiddenMethod(Object a,String methodName) throws Exception&#123;</span><br><span class="line">		Method g = a.getClass().getDeclaredMethod(methodName);</span><br><span class="line">		g.setAccessible(true);</span><br><span class="line">		g.invoke(a);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>由于包访问权限的限制，在另一个包中获取不到了C新定义的方法。但是如果知道方法名，依然可以通过反射调用所有的方法。</p>
<p>使用javap -private 可以看到包括private权限的方法在内的所有方法。因此任何人都可以获取到你这个类中方法名，然后通过反射调用他们。</p>
<p>内部类和匿名类 private域的方法也逃不过反射的查找。</p>
<h2 id="14-10-总结"><a href="#14-10-总结" class="headerlink" title="14.10 总结"></a>14.10 总结</h2><p>&emsp;&emsp;RTTI 允许匿名基类来发现类型信息。面向对象编程的目的是让我们在可以使用的地方都是用多态机制，只在必须以后使用RTTI。</p>
<p>&emsp;&emsp;然后使用多态机制的方法调用，要求我们拥有基类定义的控制权，这时候RTTI便是一种解决之道：科技城一个新类，然后添加你所需要的方法。在代码的其他地方，可以检查你自己特定的类型，并调用你自己的方法。这样不会破会对台性以及程序的扩展能力。</p>
<p>&emsp;&emsp;RTTI有时候能解决效率问题。也许你用多态用的很好，但是极端情况下可以使用RTTI。<strong>不要太早的关注程序的效率问题，这是歌 诱人的陷阱。</strong></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2019/08/10/Thinking-in-Java-第十三章/" rel="next" title="Thinking in Java 第十三章">
                <i class="fa fa-chevron-left"></i> Thinking in Java 第十三章
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2019/08/12/Thinking-in-Java-第十五章/" rel="prev" title="Thinking in Java 第十五章">
                Thinking in Java 第十五章 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            Table of Contents
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            Overview
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image" src="/images/avatar.jpg" alt="190coder">
            
              <p class="site-author-name" itemprop="name">190coder</p>
              <p class="site-description motion-element" itemprop="description">坚信持续学习就一定能超过大多数人</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">53</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">13</span>
                  <span class="site-state-item-name">categories</span>
                </a>
              </div>
            

            

          </nav>

          

          

          
          

          
          

          <div style>
  <canvas id="canvas" style="width:60%;">当前浏览器不支持canvas，请更换浏览器后再试</canvas>
</div>
<script>
(function(){

   var digit=
    [
        [
            [0,0,1,1,1,0,0],
            [0,1,1,0,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,0,1,1,0],
            [0,0,1,1,1,0,0]
        ],//0
        [
            [0,0,0,1,1,0,0],
            [0,1,1,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [1,1,1,1,1,1,1]
        ],//1
        [
            [0,1,1,1,1,1,0],
            [1,1,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,0,0],
            [0,0,1,1,0,0,0],
            [0,1,1,0,0,0,0],
            [1,1,0,0,0,0,0],
            [1,1,0,0,0,1,1],
            [1,1,1,1,1,1,1]
        ],//2
        [
            [1,1,1,1,1,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,0,0,1,1,0],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0]
        ],//3
        [
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,1,0],
            [0,0,1,1,1,1,0],
            [0,1,1,0,1,1,0],
            [1,1,0,0,1,1,0],
            [1,1,1,1,1,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,0,1,1,0],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,1,1]
        ],//4
        [
            [1,1,1,1,1,1,1],
            [1,1,0,0,0,0,0],
            [1,1,0,0,0,0,0],
            [1,1,1,1,1,1,0],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0]
        ],//5
        [
            [0,0,0,0,1,1,0],
            [0,0,1,1,0,0,0],
            [0,1,1,0,0,0,0],
            [1,1,0,0,0,0,0],
            [1,1,0,1,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0]
        ],//6
        [
            [1,1,1,1,1,1,1],
            [1,1,0,0,0,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,1,1,0,0,0],
            [0,0,1,1,0,0,0],
            [0,0,1,1,0,0,0],
            [0,0,1,1,0,0,0]
        ],//7
        [
            [0,1,1,1,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0]
        ],//8
        [
            [0,1,1,1,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,0,0],
            [0,1,1,0,0,0,0]
        ],//9
        [
            [0,0,0,0,0,0,0],
            [0,0,1,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0],
            [0,0,1,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,0,0,0,0,0]
        ]//:
    ];

var canvas = document.getElementById('canvas');

if(canvas.getContext){
    var cxt = canvas.getContext('2d');
    //声明canvas的宽高
    var H = 100,W = 700;
    canvas.height = H;
    canvas.width = W;
    cxt.fillStyle = '#f00';
    cxt.fillRect(10,10,50,50);

    //存储时间数据
    var data = [];
    //存储运动的小球
    var balls = [];
    //设置粒子半径
    var R = canvas.height/20-1;
    (function(){
        var temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(new Date());
        //存储时间数字，由十位小时、个位小时、冒号、十位分钟、个位分钟、冒号、十位秒钟、个位秒钟这7个数字组成
        data.push(temp[1],temp[2],10,temp[3],temp[4],10,temp[5],temp[6]);
    })();

    /*生成点阵数字*/
    function renderDigit(index,num){
        for(var i = 0; i < digit[num].length; i++){
            for(var j = 0; j < digit[num][i].length; j++){
                if(digit[num][i][j] == 1){
                    cxt.beginPath();
                    cxt.arc(14*(R+2)*index + j*2*(R+1)+(R+1),i*2*(R+1)+(R+1),R,0,2*Math.PI);
                    cxt.closePath();
                    cxt.fill();
                }
            }
        }
    }

    /*更新时钟*/
    function updateDigitTime(){
        var changeNumArray = [];
        var temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(new Date());
        var NewData = [];
        NewData.push(temp[1],temp[2],10,temp[3],temp[4],10,temp[5],temp[6]);
        for(var i = data.length-1; i >=0 ; i--){
            //时间发生变化
            if(NewData[i] !== data[i]){
                //将变化的数字值和在data数组中的索引存储在changeNumArray数组中
                changeNumArray.push(i+'_'+(Number(data[i])+1)%10);
            }
        }
        //增加小球
        for(var i = 0; i< changeNumArray.length; i++){
            addBalls.apply(this,changeNumArray[i].split('_'));
        }
        data = NewData.concat();
    }

    /*更新小球状态*/
    function updateBalls(){
        for(var i = 0; i < balls.length; i++){
            balls[i].stepY += balls[i].disY;
            balls[i].x += balls[i].stepX;
            balls[i].y += balls[i].stepY;
            if(balls[i].x > W + R || balls[i].y > H + R){
                balls.splice(i,1);
                i--;
            }
        }
    }

    /*增加要运动的小球*/
    function addBalls(index,num){
        var numArray = [1,2,3];
        var colorArray =  ["#3BE","#09C","#A6C","#93C","#9C0","#690","#FB3","#F80","#F44","#C00"];
        for(var i = 0; i < digit[num].length; i++){
            for(var j = 0; j < digit[num][i].length; j++){
                if(digit[num][i][j] == 1){
                    var ball = {
                        x:14*(R+2)*index + j*2*(R+1)+(R+1),
                        y:i*2*(R+1)+(R+1),
                        stepX:Math.floor(Math.random() * 4 -2),
                        stepY:-2*numArray[Math.floor(Math.random()*numArray.length)],
                        color:colorArray[Math.floor(Math.random()*colorArray.length)],
                        disY:1
                    };
                    balls.push(ball);
                }
            }
        }
    }

    /*渲染*/
    function render(){
        //重置画布宽度，达到清空画布的效果
        canvas.height = 100;
        //渲染时钟
        for(var i = 0; i < data.length; i++){
            renderDigit(i,data[i]);
        }
        //渲染小球
        for(var i = 0; i < balls.length; i++){
            cxt.beginPath();
            cxt.arc(balls[i].x,balls[i].y,R,0,2*Math.PI);
            cxt.fillStyle = balls[i].color;
            cxt.closePath();
            cxt.fill();
        }
    }

    clearInterval(oTimer);
    var oTimer = setInterval(function(){
        //更新时钟
        updateDigitTime();
        //更新小球状态
        updateBalls();
        //渲染
        render();
    },50);
}

})();
</script>



        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#第十四章-类型信息"><span class="nav-number">1.</span> <span class="nav-text">第十四章 类型信息</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#15-1-为什么需要RTTI"><span class="nav-number">1.1.</span> <span class="nav-text">15.1 为什么需要RTTI</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#15-2-Class对象"><span class="nav-number">1.2.</span> <span class="nav-text">15.2 Class对象</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-3-类型转换器先做检查"><span class="nav-number">1.3.</span> <span class="nav-text">14.3 类型转换器先做检查</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-4-注册工厂"><span class="nav-number">1.4.</span> <span class="nav-text">14.4 注册工厂</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-5-instanceof与Class的等价性"><span class="nav-number">1.5.</span> <span class="nav-text">14.5 instanceof与Class的等价性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-6-反射：运行时类型信息"><span class="nav-number">1.6.</span> <span class="nav-text">14.6 反射：运行时类型信息</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-7-动态代理"><span class="nav-number">1.7.</span> <span class="nav-text">14.7 动态代理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-8-空对象"><span class="nav-number">1.8.</span> <span class="nav-text">14.8 空对象</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-9-接口与类型信息"><span class="nav-number">1.9.</span> <span class="nav-text">14.9 接口与类型信息</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#14-10-总结"><span class="nav-number">1.10.</span> <span class="nav-text">14.10 总结</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

	
           
         
         <div style>
  <canvas id="canvas" style="width:60%;">当前浏览器不支持canvas，请更换浏览器后再试</canvas>
</div>
<script>
(function(){

   var digit=
    [
        [
            [0,0,1,1,1,0,0],
            [0,1,1,0,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,0,1,1,0],
            [0,0,1,1,1,0,0]
        ],//0
        [
            [0,0,0,1,1,0,0],
            [0,1,1,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [1,1,1,1,1,1,1]
        ],//1
        [
            [0,1,1,1,1,1,0],
            [1,1,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,0,0],
            [0,0,1,1,0,0,0],
            [0,1,1,0,0,0,0],
            [1,1,0,0,0,0,0],
            [1,1,0,0,0,1,1],
            [1,1,1,1,1,1,1]
        ],//2
        [
            [1,1,1,1,1,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,0,0,1,1,0],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0]
        ],//3
        [
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,1,0],
            [0,0,1,1,1,1,0],
            [0,1,1,0,1,1,0],
            [1,1,0,0,1,1,0],
            [1,1,1,1,1,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,0,1,1,0],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,1,1]
        ],//4
        [
            [1,1,1,1,1,1,1],
            [1,1,0,0,0,0,0],
            [1,1,0,0,0,0,0],
            [1,1,1,1,1,1,0],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0]
        ],//5
        [
            [0,0,0,0,1,1,0],
            [0,0,1,1,0,0,0],
            [0,1,1,0,0,0,0],
            [1,1,0,0,0,0,0],
            [1,1,0,1,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0]
        ],//6
        [
            [1,1,1,1,1,1,1],
            [1,1,0,0,0,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,0,0],
            [0,0,0,1,1,0,0],
            [0,0,1,1,0,0,0],
            [0,0,1,1,0,0,0],
            [0,0,1,1,0,0,0],
            [0,0,1,1,0,0,0]
        ],//7
        [
            [0,1,1,1,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,1,1,0]
        ],//8
        [
            [0,1,1,1,1,1,0],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [1,1,0,0,0,1,1],
            [0,1,1,1,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,0,1,1],
            [0,0,0,0,1,1,0],
            [0,0,0,1,1,0,0],
            [0,1,1,0,0,0,0]
        ],//9
        [
            [0,0,0,0,0,0,0],
            [0,0,1,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0],
            [0,0,1,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,1,1,1,0,0],
            [0,0,0,0,0,0,0]
        ]//:
    ];

var canvas = document.getElementById('canvas');

if(canvas.getContext){
    var cxt = canvas.getContext('2d');
    //声明canvas的宽高
    var H = 100,W = 700;
    canvas.height = H;
    canvas.width = W;
    cxt.fillStyle = '#f00';
    cxt.fillRect(10,10,50,50);

    //存储时间数据
    var data = [];
    //存储运动的小球
    var balls = [];
    //设置粒子半径
    var R = canvas.height/20-1;
    (function(){
        var temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(new Date());
        //存储时间数字，由十位小时、个位小时、冒号、十位分钟、个位分钟、冒号、十位秒钟、个位秒钟这7个数字组成
        data.push(temp[1],temp[2],10,temp[3],temp[4],10,temp[5],temp[6]);
    })();

    /*生成点阵数字*/
    function renderDigit(index,num){
        for(var i = 0; i < digit[num].length; i++){
            for(var j = 0; j < digit[num][i].length; j++){
                if(digit[num][i][j] == 1){
                    cxt.beginPath();
                    cxt.arc(14*(R+2)*index + j*2*(R+1)+(R+1),i*2*(R+1)+(R+1),R,0,2*Math.PI);
                    cxt.closePath();
                    cxt.fill();
                }
            }
        }
    }

    /*更新时钟*/
    function updateDigitTime(){
        var changeNumArray = [];
        var temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(new Date());
        var NewData = [];
        NewData.push(temp[1],temp[2],10,temp[3],temp[4],10,temp[5],temp[6]);
        for(var i = data.length-1; i >=0 ; i--){
            //时间发生变化
            if(NewData[i] !== data[i]){
                //将变化的数字值和在data数组中的索引存储在changeNumArray数组中
                changeNumArray.push(i+'_'+(Number(data[i])+1)%10);
            }
        }
        //增加小球
        for(var i = 0; i< changeNumArray.length; i++){
            addBalls.apply(this,changeNumArray[i].split('_'));
        }
        data = NewData.concat();
    }

    /*更新小球状态*/
    function updateBalls(){
        for(var i = 0; i < balls.length; i++){
            balls[i].stepY += balls[i].disY;
            balls[i].x += balls[i].stepX;
            balls[i].y += balls[i].stepY;
            if(balls[i].x > W + R || balls[i].y > H + R){
                balls.splice(i,1);
                i--;
            }
        }
    }

    /*增加要运动的小球*/
    function addBalls(index,num){
        var numArray = [1,2,3];
        var colorArray =  ["#3BE","#09C","#A6C","#93C","#9C0","#690","#FB3","#F80","#F44","#C00"];
        for(var i = 0; i < digit[num].length; i++){
            for(var j = 0; j < digit[num][i].length; j++){
                if(digit[num][i][j] == 1){
                    var ball = {
                        x:14*(R+2)*index + j*2*(R+1)+(R+1),
                        y:i*2*(R+1)+(R+1),
                        stepX:Math.floor(Math.random() * 4 -2),
                        stepY:-2*numArray[Math.floor(Math.random()*numArray.length)],
                        color:colorArray[Math.floor(Math.random()*colorArray.length)],
                        disY:1
                    };
                    balls.push(ball);
                }
            }
        }
    }

    /*渲染*/
    function render(){
        //重置画布宽度，达到清空画布的效果
        canvas.height = 100;
        //渲染时钟
        for(var i = 0; i < data.length; i++){
            renderDigit(i,data[i]);
        }
        //渲染小球
        for(var i = 0; i < balls.length; i++){
            cxt.beginPath();
            cxt.arc(balls[i].x,balls[i].y,R,0,2*Math.PI);
            cxt.fillStyle = balls[i].color;
            cxt.closePath();
            cxt.fill();
        }
    }

    clearInterval(oTimer);
    var oTimer = setInterval(function(){
        //更新时钟
        updateDigitTime();
        //更新小球状态
        updateBalls();
        //渲染
        render();
    },50);
}

})();
</script>



    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">190coder</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Gemini</a> v5.1.4</div>





<div>
    <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span id="busuanzi_container_site_pv">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
    <span class="post-meta-divider">|</span>
    <span id="busuanzi_container_site_uv">本站访客数<span id="busuanzi_value_site_uv"></span>人</span>
</div>


        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  


  











  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  

  
  
    <script type="text/javascript" src="//cdn.jsdelivr.net/gh/theme-next/theme-next-canvas-nest@1/canvas-nest.min.js"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
